﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Drawing;

using iPdf.Properties;
using SourceGrid;
using CNPOPSOFT.Controls;

namespace iPdf
{
    /// <summary>
    /// The grid control with extra helper methods to fit our needs
    /// </summary>
    [System.ComponentModel.ToolboxItem(true)]
    partial class TataGrid : TataGridBase<string>
    {
        #region Fields
        private LoadingCircle loadingCircle;

        private bool canSelectionMoveUp;
        private bool canSelectionMoveDown;
        //flag to indicate whether it's the first adding item action in current session
        private bool firstAddItem = true;

        #endregion

        #region Properties

        public bool CanSelectionMoveUp
        {
            get
            {
                UpdateSelectionRelatedMembers();
                return canSelectionMoveUp;
            }
        }

        public bool CanSelectionMoveDown
        {
            get
            {
                UpdateSelectionRelatedMembers();
                return canSelectionMoveDown;
            }
        }

        public bool SelectedItemOperable
        {
            get
            {
                return HasItems && !string.IsNullOrEmpty(OperateItem);
            }
        }

        public string OperateItem
        {
            get
            {
                string operateItem = string.Empty;
                int row = -1;
                if (SingleSelected)
                {
                    row = SelectedRowsIndex[0];
                }

                if (RowsCount == 2)
                {
                    //only one item
                    row = 1;
                }

                if (row != -1)
                {
                    string srcFileName = (string)Source.GetValueAt(row);
                    if (File.Exists(srcFileName) &&
                        FileFormat.PdfFormat.IsOneOf(srcFileName))
                    {
                        operateItem = srcFileName;
                    }
                }

                return operateItem;
            }
        }

        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        public TataGrid()
        {
            CreateLoadingCircle();
        }

        #endregion

        #region Methods
        #region Creators
        private SourceGrid.Cells.Header CreateHeader(object value)
        {
            SourceGrid.Cells.Header header = new SourceGrid.Cells.Header(value);
            header.View.Font = gridFont;
            return header;
        }

        private SourceGrid.Cells.RowHeader CreateRowHeader(object value)
        {
            SourceGrid.Cells.RowHeader rowHeader = new SourceGrid.Cells.RowHeader(value);
            rowHeader.View.Font = gridFont;
            return rowHeader;
        }

        private SourceGrid.Cells.Cell CreateFileNameCell(SourceGrid.Cells.Controllers.ToolTipText tooltip, 
                                                                                    SourceGrid.Cells.Editors.EditorBase editor,
                                                                                    string text
                                                                                    )
        {
            SourceGrid.Cells.Cell cell = CreateRegularCell(text);
            cell.ToolTipText = text;
            cell.AddController(tooltip);
            cell.Editor = editor;
            return cell;
        }

        private SourceGrid.Cells.Cell CreateRegularCell(object value)
        {
            SourceGrid.Cells.Cell cell = new SourceGrid.Cells.Cell(value);
            cell.View.Font = gridFont;
            cell.AddController(popupMenuController);
            return cell;
        }

        private void CreateLoadingCircle()
        {
            //create loading circle
            loadingCircle = new LoadingCircle();
            loadingCircle.BackColor = System.Drawing.Color.Transparent;
            loadingCircle.Color = System.Drawing.Color.Black;
            loadingCircle.ForeColor = System.Drawing.Color.Black;
            loadingCircle.InnerCircleRadius = 8;
            loadingCircle.Name = "LoadingCircle";
            loadingCircle.NumberSpoke = 24;
            loadingCircle.OuterCircleRadius = 9;
            loadingCircle.RotationSpeed = 80;
            loadingCircle.Size = new System.Drawing.Size(38, 23);
            loadingCircle.SpokeThickness = 4;
            loadingCircle.StylePreset = LoadingCircle.StylePresets.IE7;
            loadingCircle.TabIndex = 0;
            loadingCircle.Text = "Processing";
        }

        #endregion

        #region Updater

        public void UpdateOutputFolder(string folder)
        {
            for (int i = 1; i < RowsCount; ++i)
            {
                SourceGrid.Cells.Cell destCell = Destination[i];
                string path = (string)Destination.GetValueAt(i);
                destCell.Value = Path.Combine(folder, Path.GetFileName(path));
            }
        }

        public void UpdateOutputExtension()
        {
            string extension = Global.CurrentPage.DestinationFormat.Extension;
            
            for (int i = 1; i < RowsCount; ++i)
            {
                SourceGrid.Cells.Cell destCell = Destination[i];
                string path = (string)Source.GetValueAt(i);
                string destination = Global.CurrentPage.GetDestination(path, null);
                destCell.Value = Path.Combine(Path.GetDirectoryName(destination),
                                            Path.GetFileNameWithoutExtension(destination) + extension);
            }

            destinatinCellEditor.Extension = extension;
        }

        private void UpdateSelectionRelatedMembers()
        {
            int[] selectedRowsIndex = SelectedRowsIndex;
            if (!SelectionExists || AllSelected)
            {
                canSelectionMoveUp = canSelectionMoveDown = false;
                return;
            }

            int prevRowIndex = 0;
            int length = selectedRowsIndex.Length;
            canSelectionMoveUp = false;
            for (int i = 0; i < length; ++i)
            {
                int rowIndex = selectedRowsIndex[i];
                if (rowIndex != prevRowIndex + 1)
                {
                    canSelectionMoveUp = true;
                    break;
                }

                prevRowIndex = rowIndex;
            }

            if (canSelectionMoveUp == false)
            {
                canSelectionMoveDown = true;
                return;
            }

            canSelectionMoveDown = false;
            int nextRowIndex = RowsCount;
            for (int i = length - 1; i >= 0; --i)
            {
                int rowIndex = selectedRowsIndex[i];
                if (rowIndex != nextRowIndex - 1)
                {
                    canSelectionMoveDown = true;
                    return;
                }

                nextRowIndex = rowIndex;
            }
        }


        #endregion

        #region Movers
        protected void RemoveRow(int rowPos)
        {
            for (int i = rowPos + 1; i < RowsCount; ++i)
            {
                MoveUpOneRow(i);
            }

            Rows.Remove(RowsCount - 1);
            Global.MainWindow.UpdateRibbon();
        }

        public override void RemoveSelection()
        {
            base.RemoveSelection();

            Global.MainWindow.UpdateRibbon();
        }

        public override void RemoveAll()
        {
            base.RemoveAll();
            Global.MainWindow.UpdateRibbon();
            Selection_SelectionChanged(null, null);
        }

        //move the i-th row up one
        protected void MoveUpOneRow(int rowIndex)
        {
            if (rowIndex > 1 && rowIndex < RowsCount)
            {
                bool curRowSelected = Selection.IsSelectedRow(rowIndex);
                bool prevRowSelected = Selection.IsSelectedRow(rowIndex - 1);
                Rows.Move(rowIndex, rowIndex - 1);
                //move the selection to reflect the change
                Selection.SelectRow(rowIndex, prevRowSelected);
                if (prevRowSelected)
                {
                    Selection.Focus(new Position(rowIndex, Source.Index), false);
                }
                Selection.SelectRow(rowIndex - 1, curRowSelected);
                if (curRowSelected)
                {
                    Selection.Focus(new Position(rowIndex - 1, Source.Index), false);
                }
            }
        }

        //Move up the selection
        public void MoveUpSelection()
        {
            int[] rowsIndex = Selection.GetSelectionRegion().GetRowsIndex();
            bool prevRowMoved = false;
            int prevRowIndex = 0;
            for (int i = 0; i < rowsIndex.Length; ++i)
            {
                int rowIndex = rowsIndex[i];
                if (rowIndex == prevRowIndex + 1)
                {
                    //consecutive rows, we have to check if previous row was moved
                    if (prevRowMoved)
                    {
                        MoveUpOneRow(rowIndex);
                    }
                }
                else
                {
                    //not consecutive rows, simply move it up
                    MoveUpOneRow(rowIndex);
                    prevRowMoved = true;
                }

                prevRowIndex = rowIndex;
            }
        }

        protected void MoveDownOneRow(int rowIndex)
        {
            if (rowIndex < RowsCount - 1 && rowIndex >= 1)
            {
                bool curRowSelected = Selection.IsSelectedRow(rowIndex);
                bool nextRowSelected = Selection.IsSelectedRow(rowIndex + 1);
                //move the selection to reflect the change
                Selection.SelectRow(rowIndex, nextRowSelected);
                if (nextRowSelected)
                {
                    Selection.Focus(new Position(rowIndex, Source.Index), false);
                }
                Selection.SelectRow(rowIndex + 1, curRowSelected);
                if (curRowSelected)
                {
                    Selection.Focus(new Position(rowIndex + 1, Source.Index), false);
                }
                Rows.Move(rowIndex, rowIndex + 1);
            }
        }

        public void MoveDownSelection()
        {
            int[] rowsIndex = Selection.GetSelectionRegion().GetRowsIndex();
            bool nextRowMoved = false;
            int nextRowIndex = RowsCount;
            for (int i = rowsIndex.Length - 1; i >= 0; --i)
            {
                int rowIndex = rowsIndex[i];
                if (rowIndex == nextRowIndex - 1)
                {
                    //consecutive rows, we have to check if next row was moved
                    if (nextRowMoved)
                    {
                        MoveDownOneRow(rowIndex);
                    }
                }
                else
                {
                    //not consecutive rows, simply move it down
                    MoveDownOneRow(rowIndex);
                    nextRowMoved = true;
                }

                nextRowIndex = rowIndex;
            }
        }

        #endregion

        #region Overrides
        protected override void  OnMouseHover(EventArgs e)
        {
 	        base.OnMouseHover(e);

            if (!HasItems && string.IsNullOrEmpty( this.ToolTipText ) )
            {
                string message = Resources.GridToolTip;
#if !LITE
                message += Helper.NewLine + Resources.DragNDropOnUACNotice;
#endif
                this.ToolTipText = message;
                this.ToolTip.ToolTipIcon = ToolTipIcon.Info;
                this.ToolTip.ToolTipTitle = this.Name;
            }
        }

        #endregion

        private void EnableControllerAndEditor(bool enabled)
        {
            popupMenuController.Enabled = enabled;
            keyController.Enabled = enabled;
            destinatinCellEditor.EnableEdit = enabled;
        }

        private void EnableAutoSize(bool enabled)
        {
            AutoSize = enabled;
            AutoStretchColumnsToFitWidth = enabled;
            SourceGrid.AutoSizeMode autoSizeMode = enabled ? SourceGrid.AutoSizeMode.EnableAutoSize | SourceGrid.AutoSizeMode.EnableStretch :
                                                                                SourceGrid.AutoSizeMode.None;

            foreach (TataGridColumnInfo col in Columns)
            {
                if (col.Width == 0)
                {
                    col.AutoSizeMode = autoSizeMode;
                }
            }
        }

        private void EnableSorting(bool enabled)
        {
            foreach (TataGridColumnInfo colInfo in Columns)
            {
                SourceGrid.Cells.ColumnHeader header = (SourceGrid.Cells.ColumnHeader)
                    colInfo[0];
                header.AutomaticSortEnabled = colInfo.Sortable && enabled;
            }
        }

        private void Selection_SelectionChanged(object sender, SourceGrid.RangeRegionChangedEventArgs e)
        {
            UpdateSelectionRelatedMembers();
            Global.MainWindow.UpdateMoveGroup();
            if (!HasItems)
            {
                Global.MainWindow.Status = WorkStatus.Idle;
            }

            if (Global.CurrentPage.SelectionSensitive)
            {
                Global.CurrentPage.UpdatePageOnlyControls();
            }
        }

        public void Load()
        {
            InitializeControllerAndEditor();
            InstallColumnCreatorAndUpdator();

            RowsCount = 1;
            FixedRows = 1;
            FixedColumns = 1;

            Controller.AddController(keyController);

            foreach (TataGridColumnInfo column in Columns)
            {
                CreateColumnHeader(column);
            }

            this.SortedRangeRows += new SortRangeRowsEventHandler(
                                        delegate(object sender, SortRangeRowsEventArgs e)
                                        {
                                            for (int i = 1; i < RowsCount; ++i)
                                            {
                                                Id.Update(i);
                                            }
                                        });

            UpdateCells();

            AutoSizeCells();
            Selection.EnableMultiSelection = true;
            Selection.SelectionChanged += new 
                RangeRegionChangedEventHandler(Selection_SelectionChanged);
        }

        public bool AddItem(string item)
        {
            return AddItem(item, true);
        }

        public bool AddItem(string item, bool addToPage)
        {
            if (!File.Exists(item))
            {
                return false;
            }

            if (firstAddItem == true && SelectionExists && IsColumnVisible(From))
            {
                Selection.ResetSelection(false);
                firstAddItem = false;
            }

            TataRibbonPage curPage = Global.CurrentPage;
            if (!curPage.IsValidItem(item))
            {
                return false;
            }

            int row = RowsCount;
            Rows.Insert(row);
            Rows[row].Height = gridRowHeight;

            foreach (TataGridColumnInfo colInfo in Columns)
            {
                colInfo.Create(item);
            }

            Selection_SelectionChanged(null, null);
            Global.RecentFiles.Add(item);

            if (addToPage)
            {
                Global.CurrentPage.ItemList.Add(item);
            }
            return true;
        }

        public void AddItems(string[] items)
        {
            if (items != null)
            {
                foreach (string item in items)
                {
                    AddItem(item);
                }
            }

            firstAddItem = true;
        }

        public void AddLoadingCircle(int curItemIndex)
        {
            loadingCircle.Active = true;
            SourceGrid.Cells.Cell statusCell = Status[curItemIndex];
            statusCell.Value = "";
            SourceGrid.Position position = new Position(curItemIndex, Status.Index);
            LinkedControlValue linkedLoadingCircle = new SourceGrid.LinkedControlValue(loadingCircle, position);
            LinkedControls.Add(linkedLoadingCircle);
            ArrangeLinkedControls();

            //Focus the current row
            Selection.ResetSelection(false);
            Selection.SelectRow(curItemIndex, true);
            Selection.FocusRow(curItemIndex);
        }

        public void RemoveLoadingCircle(ProcessItemEventArgs e)
        {
            LinkedControlValue linkedLoadingCircle = LinkedControls.GetByControl(loadingCircle);
            LinkedControls.Remove(linkedLoadingCircle);
            SourceGrid.Cells.Cell statusCell = Status[e.Index];
            statusCell.Value = e.Status.ToString();
            if (e.Status == ItemStatus.Error)
            {
                statusCell.Tag = e.Exception;
                statusCell.RemoveController(errorController);
                statusCell.AddController(errorController);
            }
        }

        #endregion 
    }
}
